﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using System.Windows.Input;
using System.ComponentModel;
using Chess.Client.Model;
using Chess.Client.ViewModel;
using Chess.Common;
using Chess.Engine;

namespace Chess.Client.View {
    /// <summary>
    /// Defines a Chess Board Control
    /// </summary>
    internal partial class ChessBoardView : UserControl {

        private Border[] _borders;
        private ChessBoardViewModel _viewModel;
        private MainViewModel _mainViewModel;

        public ChessBoardView()
        {
            InitializeComponent();
        }

        private void OnContentLoaded(object sender, RoutedEventArgs e)
        {
            _mainViewModel = DataContext as MainViewModel;
            _viewModel = _mainViewModel.ChessBoard;
            _viewModel.Engine.MovedPiece += InitCell;
            InitCell();
        }

        private void InitCell()
        {
            Border border;
            Brush brushDark;
            Brush brushLite;
            CellContainer.Children.Clear();
            _borders = new Border[64];
            int iPos = 63;
            brushDark = new SolidColorBrush(DarkCellColor);
            brushLite = new SolidColorBrush(LiteCellColor);
            for (int y = 7; y >= 0; y--)
            {
                for (int x = 7; x >= 0; x--)
                {
                    border = new Border();
                    border.Name = "Cell" + (iPos.ToString());
                    border.BorderThickness = new Thickness(1);
                    border.Background = (((x + y) & 1) == 0) ? brushLite : brushDark;
                    border.BorderBrush = border.Background;
                    border.SetValue(Grid.ColumnProperty, x);
                    border.SetValue(Grid.RowProperty, y);
                    _borders[iPos] = border;
                    CellContainer.Children.Add(border);

                    var pieceType = _viewModel.Engine.GetPieceTypeAt((byte)x, (byte)y);
                    var pieceColor = _viewModel.Engine.GetPieceColorAt((byte) x, (byte) y);
                    if (pieceType != ChessPieceType.None)
                        border.Child = LoadFigure(pieceType, pieceColor);
                    iPos--;
                }
            }
        }
        public UserControl LoadFigure(ChessPieceType pieceType, ChessPieceColor pieceColor)
        {
            var figureName = string.Format("{0} {1}", pieceColor.ToString(), pieceType.ToString()).ToLower();
            var strUriName = string.Format("piecesets/{0}/{1}.xaml", "adventurer", figureName);
            //var strUriName = "piecesets/" + "alpha" + "/" + figureName + ".xaml";
            var uri = new Uri(strUriName, UriKind.Relative);
            var userControl = App.LoadComponent(uri) as UserControl;
            return userControl;
        }

        #region Board creation

        /// <summary>
        /// Static Ctor
        /// </summary>
        static ChessBoardView() {
            LiteCellColorProperty   = DependencyProperty.Register("LiteCellColor",
                                                                  typeof(Color),
                                                                  typeof(ChessBoardView),
                                                               new FrameworkPropertyMetadata(Colors.Moccasin,
                                                                                             FrameworkPropertyMetadataOptions.AffectsRender,
                                                                                             ColorInfoChanged));
            DarkCellColorProperty   = DependencyProperty.Register("DarkCellColor",
                                                               typeof(Color),
                                                               typeof(ChessBoardView),
                                                               new FrameworkPropertyMetadata(Colors.SaddleBrown,
                                                                                             FrameworkPropertyMetadataOptions.AffectsRender,
                                                                                             ColorInfoChanged));
            WhitePieceColorProperty   = DependencyProperty.Register("WhitePieceColor",
                                                               typeof(Color),
                                                               typeof(ChessBoardView),
                                                               new FrameworkPropertyMetadata(Colors.White,
                                                                                             FrameworkPropertyMetadataOptions.AffectsRender,
                                                                                             ColorInfoChanged));
            BlackPieceColorProperty   = DependencyProperty.Register("BlackPieceColor",
                                                                    typeof(Color),
                                                                    typeof(ChessBoardView),
                                                                    new FrameworkPropertyMetadata(Colors.Black,
                                                                                                  FrameworkPropertyMetadataOptions.AffectsRender,
                                                                                                  ColorInfoChanged));
        }

        private static void ColorInfoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

        /// <summary>Lite Cell Color property</summary>
        public static readonly DependencyProperty LiteCellColorProperty;
        /// <summary>Dark Cell Color property</summary>
        public static readonly DependencyProperty DarkCellColorProperty;
        /// <summary>White Pieces Color property</summary>
        public static readonly DependencyProperty WhitePieceColorProperty;
        /// <summary>Black Pieces Color property</summary>
        public static readonly DependencyProperty BlackPieceColorProperty;

        #region Properties

        /// <summary>
        /// Image displayed to the button
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [Bindable(true)]
        [Category("Brushes")]
        [Description("Lite Cell Color")]
        public Color LiteCellColor {
            get {
                return ((Color)GetValue(LiteCellColorProperty));
            }
            set {
                SetValue(LiteCellColorProperty, value);
            }
        }

        /// <summary>
        /// Image displayed to the button
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [Bindable(true)]
        [Category("Brushes")]
        [Description("Dark Cell Color")]
        public Color DarkCellColor {
            get {
                return ((Color)GetValue(DarkCellColorProperty));
            }
            set {
                SetValue(DarkCellColorProperty, value);
            }
        }

        /// <summary>
        /// Image displayed to the button
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [Bindable(true)]
        [Category("Brushes")]
        [Description("White Pieces Color")]
        public Color WhitePieceColor {
            get {
                return ((Color)GetValue(WhitePieceColorProperty));
            }
            set {
                SetValue(WhitePieceColorProperty, value);
            }
        }

        /// <summary>
        /// Image displayed to the button
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [Bindable(true)]
        [Category("Brushes")]
        [Description("Black Pieces Color")]
        public Color BlackPieceColor {
            get {
                return ((Color)GetValue(BlackPieceColorProperty));
            }
            set {
                SetValue(BlackPieceColorProperty, value);
            }
        }

        #endregion

        private async void OnMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var engine = _viewModel.Engine;
            BytePoint ptCell;
            if (GetCellFromPoint(e, out ptCell))
            {
                InitCell();
                var selectedFigure = engine.GetPieceTypeAt(ptCell.X, ptCell.Y);
                var selectedCellColor = engine.GetPieceColorAt(ptCell.X, ptCell.Y);
                var border = _borders[ptCell.Position];

                
                border.BorderBrush = !_viewModel.Selected ? Brushes.Black : border.Background;
                border.BorderThickness = new Thickness(1);

                if (_viewModel.Selected)
                {
                    var prevSelectedCellColor = engine.GetPieceColorAt(_viewModel.SelectedCell.X,
                                                                       _viewModel.SelectedCell.Y);
                    var isValidMove = engine.IsValidMove(_viewModel.SelectedCell.X, _viewModel.SelectedCell.Y, ptCell.X,
                                                         ptCell.Y);
                    isValidMove = isValidMove && prevSelectedCellColor == engine.WhoseMove;

                    if (_mainViewModel.CanMove)
                    {
                        if (isValidMove)
                        {
                            engine.MovePiece(_viewModel.SelectedCell.X, _viewModel.SelectedCell.Y, ptCell.X, ptCell.Y);
                            _mainViewModel.CanMove = false;
                            if (_mainViewModel.AntagonistName != null)
                                await _mainViewModel.ClientService.MovePiece(_mainViewModel.AntagonistName,  _viewModel.SelectedCell, ptCell);
                        }
                    }
                    InitCell();
                    // clean cells selection
                    var selectedBorder = _borders[_viewModel.SelectedCell.Position];
                    selectedBorder.BorderBrush = selectedBorder.Background;
                    selectedBorder.BorderThickness = new Thickness(0);
                }
                else
                {
                    _viewModel.SelectedCell = ptCell;

                    if (selectedCellColor == engine.WhoseMove && _mainViewModel.CanMove)
                    {
                        // highlight possible moves
                        var validMoves = engine.GetValidMoves(ptCell.X, ptCell.Y);
                        if (validMoves != null)
                            foreach (byte[] move in validMoves)
                            {
                                var pos = move[0] + move[1] * 8;
                                _borders[pos].Background = Brushes.SkyBlue;
                            }
                    }
                }

                _viewModel.Selected = !_viewModel.Selected;

            }
        }

        public bool GetCellFromPoint(MouseEventArgs e, out BytePoint ptCell)
        {
            bool bRetVal;

            var pt = e.GetPosition(CellContainer);
            var dActualHeight = CellContainer.ActualHeight;
            var dActualWidth = CellContainer.ActualWidth;
            var iCol = (int)(pt.X * 8 / dActualWidth);
            var iRow = (int)(pt.Y * 8 / dActualHeight);
            if (iCol >= 0 && iCol < 8 && iRow >= 0 && iRow < 8)
            {
                ptCell = new BytePoint((byte) iCol, (byte) iRow);
                bRetVal = true;
            }
            else
            {
                ptCell = new BytePoint(9, 9);
                bRetVal = false;
            }
            return bRetVal;
        }
    }
}
